package com.kelaite.procurement.service.impl;

import java.util.Date;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.transaction.Transactional;

import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.criterion.Restrictions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.kelaite.procurement.constants.MilestoneTypeEnum;
import com.kelaite.procurement.dto.PurchaseOrderDTO;
import com.kelaite.procurement.dto.PurchaseOrderPaymentDTO;
import com.kelaite.procurement.entity.TPurchaseOrder;
import com.kelaite.procurement.entity.TPurchaseOrderPayment;
import com.kelaite.procurement.entity.TSalesOrderPayment;
import com.kelaite.procurement.exception.AmountExceedLimitException;
import com.kelaite.procurement.exception.BusinessException;
import com.kelaite.procurement.exception.DuplicateObjectException;
import com.kelaite.procurement.repository.PurchaseOrderPaymentRepository;
import com.kelaite.procurement.repository.PurchaseOrderRepository;
import com.kelaite.procurement.repository.SalesOrderPaymentRepository;
import com.kelaite.procurement.repository.SalesOrderRepository;
import com.kelaite.procurement.service.PurchaseOrderPaymentService;
import com.kelaite.procurement.utils.ConvertUtil;
import com.kelaite.procurement.utils.CurrentUserUtils;

@Service
@Transactional
public class PurchaseOrderPaymentServiceImpl implements
		PurchaseOrderPaymentService {

	private static Logger logger = Logger
			.getLogger(PurchaseOrderPaymentServiceImpl.class);

	@Autowired
	private PurchaseOrderPaymentRepository purchaseOrderPaymentRepository;

	@Autowired
	private PurchaseOrderRepository purchaseOrderRepository;

	@Autowired
	private SalesOrderRepository salesOrderRepository;

	@Autowired
	private SalesOrderPaymentRepository salesOrderPaymentRepository;

	@PersistenceContext
	private EntityManager em;

	@Override
	public PurchaseOrderPaymentDTO save(PurchaseOrderPaymentDTO paymentDto) {

		try {
			//
			if (null == paymentDto) {
				throw new BusinessException("PurchaseOrderPaymentDTO is null. ");
			}
			// PurchaseOrder
			Long purchaseOrderId = paymentDto.getPurchaseOrderId();
			if (null == purchaseOrderId || purchaseOrderId <= 0) {
				throw new BusinessException(
						String.format(
								"PurchaseOrderPaymentDTO.purchaseOrderId[%s] is illegal. ",
								purchaseOrderId));
			}
			// check重复性添加
			int cnt = this.countByPurchaseOrderIdAndDisplayOrderNo(
					purchaseOrderId, paymentDto.getDisplayOrderNo());
			if (cnt > 0) {
				String msg = String
						.format("Repeat add milestone. PurchaseOrderId[%s], Milestone[%s]",
								purchaseOrderId,
								MilestoneTypeEnum.parse(
										paymentDto.getMilestoneType())
										.getDesc());
				logger.error(msg);
				throw new DuplicateObjectException(msg);
			}
			//
			TPurchaseOrder dbPurchaseOrder = purchaseOrderRepository
					.findOne(purchaseOrderId);
			if (null == dbPurchaseOrder) {
				throw new BusinessException(String.format(
						"PurchaseOrderPaymentDTO[%s] is not exsist. ",
						purchaseOrderId));
			}
			// check planAmount是否超出限额
			Long totalPlanAmount = purchaseOrderPaymentRepository
					.getTotalPlanAmountForAddCheck(purchaseOrderId);
			if (null == totalPlanAmount) {
				totalPlanAmount = 0L;
			}
			totalPlanAmount += paymentDto.getPlanAmount();
			if (dbPurchaseOrder.getPrice() < totalPlanAmount) {
				String msg = String
						.format("TotalPlanAmount[%s] exceed PurchaseOrder[id=%s]'s price[%s]; Input's planAmount[%s]. ",
								totalPlanAmount, purchaseOrderId,
								dbPurchaseOrder.getPrice(),
								paymentDto.getPlanAmount());
				logger.error(msg);
				throw new AmountExceedLimitException(msg);
			}
			// Date
			Date now = new Date();
			// CurrentUser
			String cUser = CurrentUserUtils.getInstance().getUsername();
			//
			// Save PurchaseOrderPayment
			TPurchaseOrderPayment dbPurchaseOrderPayment = ConvertUtil
					.convertObj(paymentDto, TPurchaseOrderPayment.class);
			dbPurchaseOrderPayment.setBilledTime(now);
			dbPurchaseOrderPayment.setCreatedBy(cUser);
			dbPurchaseOrderPayment.setGmtCreateTime(now);
			dbPurchaseOrderPayment.setGmtUpdateTime(now);
			dbPurchaseOrderPayment.setPaidAmount(0L);
			dbPurchaseOrderPayment.setPaidTime(now);
			dbPurchaseOrderPayment.setPercentage(Math.round(paymentDto
					.getPlanAmount() / dbPurchaseOrder.getPrice()));
			dbPurchaseOrderPayment.settPurchaseOrder(dbPurchaseOrder);
			dbPurchaseOrderPayment.setUpdatedBy(cUser);
			dbPurchaseOrderPayment = purchaseOrderPaymentRepository
					.save(dbPurchaseOrderPayment);
			//
			// Save SalesOrderPayment
			TSalesOrderPayment dbSalesOrderPayment = ConvertUtil.convertObj(
					dbPurchaseOrderPayment, TSalesOrderPayment.class);
			dbSalesOrderPayment.setId(null);
			dbSalesOrderPayment.settSalesOrder(salesOrderRepository
					.findBySalesOrderNo(dbPurchaseOrder.getSalesOrderNo()));
			salesOrderPaymentRepository.save(dbSalesOrderPayment);
			return ConvertUtil.convertObj(dbPurchaseOrderPayment,
					PurchaseOrderPaymentDTO.class);
		} catch (Exception e) {
			logger.error("save PurchaseOrderPayment occurs exception. ", e);
			if (e instanceof AmountExceedLimitException) {
				throw e;
			} else {
				throw new BusinessException(
						"save PurchaseOrderPayment occurs exception. ", e);
			}
		}
	}

	@Override
	public TPurchaseOrderPayment getObject(Long id) {

		return purchaseOrderPaymentRepository.findOne(id);
	}

	@Override
	public List<TPurchaseOrderPayment> getAll() {

		return this.purchaseOrderPaymentRepository.findAll();
	}

	@Override
	public void deleteByObject(TPurchaseOrderPayment persistence) {

		this.purchaseOrderPaymentRepository.delete(persistence);
	}

	@Override
	public void deleteByPrimaryKey(Long id) {

		this.purchaseOrderPaymentRepository.delete(id);
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<TPurchaseOrderPayment> getByProperty(String property,
			Object value) {

		Session session = (org.hibernate.Session) em.getDelegate();
		Criteria criteria = session.createCriteria(TPurchaseOrderPayment.class)
				.add(Restrictions.eq(property, value));
		return criteria.list();
	}

	@Override
	public List<PurchaseOrderPaymentDTO> getByPurchaseOrder(
			PurchaseOrderDTO purchaseOrderDTO) {

		if (null == purchaseOrderDTO || null == purchaseOrderDTO.getId()) {
			throw new BusinessException("purchaseOrderDTO is null. ");
		}
		List<TPurchaseOrderPayment> dbPaymentList = purchaseOrderPaymentRepository
				.findByTPurchaseOrderOrderByDisplayOrderNoAsc(ConvertUtil
						.convertObj(purchaseOrderDTO, TPurchaseOrder.class));
		return ConvertUtil.convertList(dbPaymentList,
				PurchaseOrderPaymentDTO.class);
	}

	@Override
	public PurchaseOrderPaymentDTO update(
			PurchaseOrderPaymentDTO orderPaymentDTO) {

		//
		if (null == orderPaymentDTO) {
			throw new BusinessException("orderPaymentDTO is null. ");
		}
		//
		if (null == orderPaymentDTO.getId() || orderPaymentDTO.getId() <= 0) {
			throw new BusinessException(String.format(
					"PurchaseOrderPaymentDTO's id[%s] is illegal. ",
					orderPaymentDTO.getId()));
		}
		// check total plan amount
		Float price = purchaseOrderRepository
				.findPriceByOrderId(orderPaymentDTO.getPurchaseOrderId());
		Long totalPlanAmount = purchaseOrderPaymentRepository
				.getTotalPlanAmountForUpdateCheck(
						orderPaymentDTO.getPurchaseOrderId(),
						orderPaymentDTO.getId());
		if (null == totalPlanAmount) {
			totalPlanAmount = 0L;
		}
		totalPlanAmount += orderPaymentDTO.getPlanAmount();
		if (price < totalPlanAmount) {
			String msg = String
					.format("TotalPlanAmount[%s] exceed PurchaseOrder[id=%s]'s price[%s]; Input's planAmount[%s]. ",
							totalPlanAmount,
							orderPaymentDTO.getPurchaseOrderId(), price,
							orderPaymentDTO.getPlanAmount());
			logger.error(msg);
			throw new AmountExceedLimitException(msg);
		}
		//
		int rt = purchaseOrderPaymentRepository.updatePurchaseOrderPayment(
				orderPaymentDTO.getId(), orderPaymentDTO
						.getOrderPaymentRemark(),
				orderPaymentDTO.getPlanTime(), orderPaymentDTO.getRealTime(),
				orderPaymentDTO.getPlanAmount(), orderPaymentDTO
						.getBilledAmount(), orderPaymentDTO.getIncreamentTax(),
				orderPaymentDTO.getAmountWithoutTax(), orderPaymentDTO
						.getRemark(), new Date(), CurrentUserUtils
						.getInstance().getUsername());
		if (rt == 1) {
			return ConvertUtil.convertObj(purchaseOrderPaymentRepository
					.getOne(orderPaymentDTO.getId()),
					PurchaseOrderPaymentDTO.class);
		} else {
			throw new BusinessException("update PurchaseOrderPayment failed. "
					+ orderPaymentDTO.toString());
		}
	}

	@Override
	public int countByPurchaseOrderId(Long purchaseOrderId) {

		if (null == purchaseOrderId || purchaseOrderId <= 0) {
			throw new BusinessException(String.format(
					"purchaseOrderId[%s] is illegal. ", purchaseOrderId));
		}
		return purchaseOrderPaymentRepository
				.countByPurchaseOrderId(purchaseOrderId);
	}

	@Override
	public int countByPurchaseOrderIdAndDisplayOrderNo(Long puchaseOrderId,
			String displayOrderNo) {

		if (puchaseOrderId == null || puchaseOrderId <= 0) {
			String msg = String.format("PurchaseOrderId[%s] is illegal. ",
					puchaseOrderId);
			logger.error(msg);
			throw new BusinessException(msg);
		}
		if (StringUtils.isBlank(displayOrderNo)) {
			throw new BusinessException("DisplayOrderNo is null. ");
		}
		return purchaseOrderPaymentRepository
				.countByPurchaseOrderIdAndDisplayOrderNo(puchaseOrderId,
						displayOrderNo);
	}

	@Override
	public void updatePurchaseInvoiceStatus(Boolean isStatus1,
			Long purchasePaymentId, int invoceStatus) {
		String cUser = CurrentUserUtils.getInstance().getUsername();
		if(isStatus1)
		{
			//发票状态1确认
			this.purchaseOrderPaymentRepository.updatePurchaseInvoiceStatus1(purchasePaymentId, invoceStatus, new Date(), cUser);
		}
		else
		{
			//发票状态2确认
			this.purchaseOrderPaymentRepository.updatePurchaseInvoiceStatus2(purchasePaymentId, invoceStatus, new Date(), cUser);
		}
	}

	@Override
	public void updatePurchaseReportStatus(Boolean isStatus1,
			long purchasePaymentId, int reportStatus) {
		String cUser = CurrentUserUtils.getInstance().getUsername();
		if(isStatus1)
		{
			//验证报告状态1确认
			this.purchaseOrderPaymentRepository.updatePurchaseReportStatus(purchasePaymentId, reportStatus, new Date(), cUser);
		}
		else
		{
			//验证报告状态2确认(暂时还未发现两个状态表，待定)
			this.purchaseOrderPaymentRepository.updatePurchaseReportStatus(purchasePaymentId, reportStatus, new Date(), cUser);
		}
		
	}
	
	
	
}
